# BSD3.0
# cili@163.com

import tkinter as tk
import random
from tkinter import messagebox


class App(tk.Tk):
    BUCKET_NUM = 5
    TITLE = '桶排序'
    NUMS_LENGTH = 25
    STEP = 0
    INTERVAL = 200
    LABEL_WIDTH=80

    def __init__(self):
        super().__init__()
        self.title(self.TITLE)
        self.resizable(False, False)

        self.buckets_data = [[] for _ in range(self.BUCKET_NUM)]
        self.buckets_data_str = [tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar()]
        [v.set('') for v in  self.buckets_data_str]
        self.buckets=[self.create_bucket(index,str_val) for index, str_val in enumerate(self.buckets_data_str)]

        self.data = [random.randint(0, 10 * self.BUCKET_NUM) for _ in range(self.NUMS_LENGTH)]
        tk.Button(self, text=f"原始数据", width=16).grid(row=self.BUCKET_NUM + 1, column=0, sticky="nsew", padx=5,pady=5)
        self.data_label = tk.Label(self, anchor='w', bg='white', width=self.LABEL_WIDTH)
        self.data_label.config(text=f"{', '.join(map(str, self.data))}")
        self.data_label.grid(row=self.BUCKET_NUM + 1, column=1, columnspan=4, sticky="nsew", padx=5, pady=5)

        buttons = [('1. 按桶分组', self.group_by_bucket), ('2. 桶内排序', self.sort_within_bucket),
                   ('3. 组合结果', self.combine_results), ('自动执行', self.auto_execute), ('重置数据', self.reset_data)]
        self.cmd_buttons = [tk.Button(self, text=text, command=func, width=16) for index, (text, func) in
                            enumerate(buttons)]
        [button.grid(row=self.BUCKET_NUM + 2, column=index, sticky='nsew', padx=5, pady=5) for index, button in
         enumerate(self.cmd_buttons)]

        self.update_cmd_UI()
        self.center_window()

    def create_bucket(self,index,str_val):
        button = tk.Button(self, text=f" {10*index}到{10*(index + 1)-1}", width=16)
        button.grid(row=index, column=0, sticky="nsew", padx=5, pady=5)
        label = tk.Label(self, textvariable=str_val, anchor='w', bg='white', width=self.LABEL_WIDTH)
        label.grid(row=index, column=1, columnspan=4, sticky="nsew", padx=5, pady=5)
        return label

    def update_cmd_UI(self,state='normal'):
        [button.config(state='disable') for button in self.cmd_buttons]
        self.cmd_buttons[self.STEP].config(state=state)
        self.cmd_buttons[-2].config(state=state)
        self.cmd_buttons[-1].config(state=state)

    def update_bucket_ui(self,bucket,bg='white'):
        bucket.config(bg=bg)
        self.after(self.INTERVAL)
        self.update()

    def sort_a_bucket(self,index,bucket_data=None):
        if bucket_data is None: bucket_data = self.buckets_data[index]
        self.update_bucket_ui(self.buckets[index],'lightgreen')
        bucket_data.sort()
        text = ', '.join(map(str, self.buckets_data[index]))
        self.buckets_data_str[index].set(text)
        self.update_bucket_ui(self.buckets[index],'lightgreen')
        self.update_bucket_ui(self.buckets[index])

    def reset_data(self):
        r = messagebox.askyesno('重置', '重置数据吗？')
        if not r : return
        self.buckets_data = [[] for _ in range(self.BUCKET_NUM)]
        self.data = [random.randint(1, 10 * self.BUCKET_NUM) for _ in range(self.NUMS_LENGTH)]
        self.data_label.config(text=f"{', '.join(map(str, self.data))}")
        [v.set('') for v in self.buckets_data_str]
        self.STEP = 0
        self.update_cmd_UI()

    def group_action(self,num):
        index = num // 10 if num != 10 * self.BUCKET_NUM else num // 10 - 1
        self.buckets_data[index].append(num)
        text = ', '.join(map(str, self.buckets_data[index]))
        self.buckets_data_str[index].set(text)
        self.update_bucket_ui(self.buckets[index], 'lightblue')
        self.update_bucket_ui(self.buckets[index])

    def group_by_bucket(self):
        self.update_cmd_UI('disable')
        self.focus_force()
        [self.group_action(num) for num in self.data]
        self.STEP = self.STEP + 1
        self.update_cmd_UI()

    def sort_within_bucket(self):
        self.update_cmd_UI('disable')
        self.focus_force()
        [self.sort_a_bucket(index,bucket_data) for index,bucket_data in enumerate(self.buckets_data)]
        self.STEP = self.STEP + 1
        self.update_cmd_UI()

    def combine_results(self):
        result = [str(item) for bucket_data in self.buckets_data for item in bucket_data]
        messagebox.showinfo('排序结果', f'{" , ".join(result)}')
        self.cmd_buttons[self.STEP].config(state='normal')
        self.cmd_buttons[-1].config(state='normal')
        self.cmd_buttons[-2].config(state='normal')

    def auto_action(self,button,cmd):
        button.config(bg='lightblue')
        cmd()
        button.config(bg='SystemButtonFace')

    def auto_execute(self):
        [button.config(state='disable') for button in self.cmd_buttons]
        cmds = [self.group_by_bucket, self.sort_within_bucket, self.combine_results]
        [self.auto_action(self.cmd_buttons[i],cmds[i]) for i in range(self.STEP, 3)]

    def center_window(self):
        self.update_idletasks()
        x = (self.winfo_screenwidth() - self.winfo_reqwidth()) // 2
        y = (self.winfo_screenheight() - self.winfo_reqheight()) // 2
        self.geometry(f'+{x}+{y}')
        self.deiconify()

if __name__ == "__main__":
    app = App()
    app.mainloop()
